package com.tas.movies
{
	import flash.utils.ByteArray;
	
	public class MovieProperty
	{												
		/**
		 * Constructor
		 *  
		 * @param name property name
		 * @param type property type enumeration
		 * @param value value as bytes		 
		 */		
		public function MovieProperty( name:String, type:String, value:ByteArray )
		{
			_name  = name;
			_type  = type;
			_value = value;
		}
		
		public static const TYPE_LITTLE_ENDIAN : String = "kTypeLittleEndian";
		public static const TYPE_BIG_ENDIAN    : String = "kTypeBigEndian";
		public static const TYPE_FLAGS         : String = "kTypeFlags";		
		public static const TYPE_UTF8_STRING   : String = "kTypeUTF8String";
		public static const TYPE_UTF16_STRING  : String = "kTypeUTF16String";
		
		private var _name  : String;
		private var _type  : String;
		private var _value : ByteArray;
		
		public function get type() : String
		{
			return _type;
		}
		
		public function get name() : String
		{
			return _name;
		}
		
		/**
		 * Get the length of the byte array that
		 * stores the raw value
		 *  
		 * @return 		 
		 */		
		public function getLength() : int
		{
			if( _value != null ){
				return _value.length;
			}else{
				return 0;
			}
		}
		
		/**
		 * Convert the raw bytes to a logical value based
		 * on the type enumeration
		 *  
		 * @return 		 
		 */		
		public function getValue() : *
		{
			switch( _type ){
				case TYPE_FLAGS:
					return _value[0];
					break; 
				case TYPE_LITTLE_ENDIAN:
					return read32( _value );
					break;
				case TYPE_UTF8_STRING:
					return _value.toString();
					break;
				case TYPE_UTF16_STRING:
					return readUTF16( _value );
					break;
					
			}
			
			throw new Error( "Unknown enumeration: " + _type );
		}
		
		/**
		 * Interpret a flag value at a given position within the byte.
		 *  
		 * @param bit the position to evaluate
		 * 
		 * @return the boolean representation of the flag 		 
		 */		
		public function getFlag( bit:int ) : Boolean
		{
			if( _type != TYPE_FLAGS ){
				throw new Error( "Attempted to read flag bit from non TYPE_FLAGS property" );
			}
			
			return Boolean( 1 & _value[0] >> bit );
		}
		
		protected function read16( high:uint, low:uint ) : uint
		{
			var o : uint = high | low << 8;
			
			return o;
		}
		
		protected function read32( target:ByteArray ) : uint
		{
			var o : uint = target[0] | target[1] << 8 | target[2] << 16 | target[3] << 32;
			
			return o;
		}
		
		protected function readUTF16( target:ByteArray ) : String
		{
			var o : String = "";					
			for( var i:int = 0; i < target.length; i+=2 ){
				o += String.fromCharCode( read16(target[i], target[i+1]) );
			}
			
			return o;
		}
		
		/**
		 * Converts a uint into a string in the format "0x123456789ABCDEF". 
		 * This function is quite useful for displaying hex colors as text.
		 * The function <code>toString(radix:uint)</code> does a similar job but doesn't include
		 * "0x" at the beginning of the result nor does it include leading zeroes.
		 * 
		 * @author Mims H. Wright
		 * 
		 * @use getNumberAsHexString(255); // 0xFF
		 * 		getNumberAsHexString(0xABCDEF); // 0xABCDEF
		 * 		getNumberAsHexString(0x00FFCC); // 0xFFCC
		 * 		getNumberAsHexString(0x00FFCC, 6); // 0x00FFCC
		 * 
		 * 
		 * @param number The number to convert to hex. Note, numbers larger than 0xFFFFFFFF may produce unexpected results.
		 * @param minimumLength The smallest number of hexits to include in the output. 
		 * 			Missing places will be filled in with 0's. 
		 * 			e.g. getNumberAsHexString(0xFF33, 6); // results in "0x00FF33"
		 * @return String representation of the number as a string starting with "0x" 
		 */
		public function getNumberAsHexString(number:uint, minimumLength:uint = 1):String {
			// A hexit is the base-16 equivelant of a digit. 
			var hexit:uint = 0;
			// The string that will be output at the end of the function.
			var string:String = "";
			
			// otherwise, loop through all hexits in the number
			while (number > 0 || minimumLength > 0) {
				minimumLength--;
				
				// get the first hexit from the number by masking the rest
				hexit = number & 0xF;
				// convert the digits over 9 into letters
				switch(hexit) {
					case 0xA: string = "A" + string; break;
					case 0xB: string = "B" + string; break;
					case 0xC: string = "C" + string; break;
					case 0xD: string = "D" + string; break;
					case 0xE: string = "E" + string; break;
					case 0xF: string = "F" + string; break;
					default: string = hexit.toString() + string;
				}
				// erase the hexit from the original number
				number >>>= 4;
			}
			
			return "0x" + string;
		}

	}
}